<?php
/**
 * Created by User: wene<china_wangyu@aliyun.com> Date: 2019/4/11 Time: 14:58
 */

namespace think\restful\command;

use think\restful\exception\ApiException;
use think\restful\helper\Helper;
use think\console\Command;
use think\console\Input;
use think\console\input\Option;
use think\console\input\Argument;
use think\console\Output;

/**
 * Class Make 创建API文档（markdown文件）
 * @package \think\restful\command
 */
class Make extends Command
{
    protected $config;
    protected $path;
    protected $data;

    public function __construct($name = null)
    {
        parent::__construct($name);
        $this->config = config('api.');
    }

    /**
     * 命令行配置文件
     */
    protected function configure()
    {
        $this->setName('api:make')
            ->addOption('name', 'N', Option::VALUE_REQUIRED,
                '文档名称',
                'API接口文档')
            ->setDescription('生成 API 接口文档，markdown 格式');
    }

    /**
     * 执行函数
     * @param \think\console\Input $input
     * @param \think\console\Output $output
     * @return int|void|null
     */
    protected function execute(Input $input, Output $output)
    {
        try{
            $options = $input->getOptions();
            $this->data = Helper::getApiVersionReflexData($this->config);
            $this->path = env('ROOT_PATH').DIRECTORY_SEPARATOR.$options['name'].date('Y-m-d H').'.md';
            $this->toMarkdown();
            $this->output->writeln(" API markdown 接口文档地址: ".$this->path);
        }catch (\Exception $exception){
            $this->output->writeln(" make API doc markdown file: ".$exception->getMessage());
        }
    }

    // API文档创建
    private function toMarkdown():void {
        try{
            $this->toMarkdownToc();
            $this->toMarkdownApi();
        }catch (\Exception $exception){
            ApiException::exception('文档创建失败~');
        }
    }

    // API接口文档的TOC
    private function toMarkdownToc()
    {
        Helper::toMarkdownToc($this->data,$this->path);
    }

    // API文档输出
    private function toMarkdownApi():void {
        $fileContent = '';
        foreach ($this->data as $versionkey => $versionData){
            $fileContent .= '# '.Helper::cleanText($versionkey).PHP_EOL.PHP_EOL;
            foreach ($versionData as $objects){
                $fileContent .= $this->toMarkdownClass($objects['object']);
                $fileContent .= $this->toMarkdownAction($objects['methods']);
            }
        }
        Helper::write($this->path,$fileContent);
    }

    // 输出API接口类
    private function toMarkdownClass(array $objectData = []):?string {
        return Helper::toMarkdownClass($objectData);
    }

    // 输出API接口方法
    private function toMarkdownAction(array $actionDatas = []):?string {
        $fileContent = '';
        if(!empty($actionDatas)) {
            foreach ($actionDatas as $actionKey => $actionData) {
                foreach ($actionData as $index => $item) {
                    $fileContent .= call_user_func_array(array(new self(),
                        'toMarkdownAction' . ucfirst($index)),
                        array($item, $index,$actionKey));
                }
            }
        }
        return $fileContent;
    }

    # 写模型方法参数：doc
    private function toMarkdownActionDoc($item,$index,$actionKey){
        $fileContent ='### '.Helper::cleanText($actionKey.$item['value']).PHP_EOL.PHP_EOL;
        return $fileContent;
    }

    # 写模型方法参数：route
    private function toMarkdownActionRoute($item,$index,$actionKey){
        $fileContent ='- `['.strtoupper($index).']` '.$item['route'].PHP_EOL.PHP_EOL;
        $fileContent .='- `[METHOD]` '.$item['method'].PHP_EOL.PHP_EOL;
        return $fileContent;
    }

    # 写模型方法参数：param
    private function toMarkdownActionParam($item,$index,$actionKey){
        $fileContent = '- `['.strtoupper($index).']` 参数'.PHP_EOL.PHP_EOL;
        $fileContent .= '| 参数名称 | 参数类型 | 参数文档 | 参数 `filter` | 参数默认 |'.PHP_EOL;
        $fileContent .= '| :----: | :----: | :----: | :----: | :----: |'.PHP_EOL;
        foreach ($item as $value){
            $fileContent .= '| '.$value['name'].' | '.$value['type'].' | '.$value['doc'].' | '.
                str_replace('|','-',$value['rule']).' | '.$value['default'].' |'.PHP_EOL;
        }
        $fileContent .= PHP_EOL.PHP_EOL;
        return $fileContent;
    }

    # 写模型方法参数：success
    private function toMarkdownActionSuccess($item,$index,$actionKey){
        $fileContent = '- `['.strtoupper($index).']` 响应'.PHP_EOL.PHP_EOL;
        $fileContent .= '```json'.PHP_EOL;
        $fileContent .= $item['value'].PHP_EOL;
        $fileContent .= '```'.PHP_EOL;
        $fileContent .= PHP_EOL.PHP_EOL;
        return $fileContent;
    }

    # 写模型方法参数：error
    private function toMarkdownActionError($item,$index,$actionKey){
        return $this->toMarkdownActionSuccess($item,$index,$actionKey);
    }
}